import time
import psutil
import logging
import threading
from typing import Dict, Any, List, Optional
import json
import os
from datetime import datetime

class PerformanceTracker:
    """
    性能追踪器，用于监控和收集测试执行过程中的性能数据
    - CPU使用率
    - 内存使用情况
    - 执行时间统计
    - 吞吐量计算
    - 性能提升分析
    """
    
    def __init__(self):
        """
        初始化性能追踪器
        """
        # 开始时间
        self.start_time = None
        self.end_time = None
        
        # 性能数据收集
        self.metrics = {
            'cpu_usage': [],  # CPU使用率历史
            'memory_usage': [],  # 内存使用历史（MB）
            'execution_times': {},  # 各阶段执行时间
            'throughput': {},  # 吞吐量数据
            'resource_utilization': {}  # 资源利用率
        }
        
        # 收集间隔（秒）
        self.collection_interval = 1.0
        
        # 收集线程
        self.collecting_thread = None
        self.running = False
        
        # 初始化日志
        self.logger = logging.getLogger('PerformanceTracker')
        
        # 基准数据（用于比较）
        self.baseline_data = None
        
        # 阶段开始时间记录
        self.phase_start_times = {}
        
        self.logger.info("性能追踪器初始化完成")
    
    def start(self):
        """
        开始性能追踪
        """
        self.start_time = time.time()
        self.running = True
        
        # 启动数据收集线程
        self.collecting_thread = threading.Thread(target=self._collect_metrics, daemon=True)
        self.collecting_thread.start()
        
        self.logger.info("性能追踪开始")
    
    def stop(self) -> Dict[str, Any]:
        """
        停止性能追踪并返回收集的数据
        
        Returns:
            性能数据字典
        """
        if not self.start_time:
            self.logger.warning("性能追踪尚未开始")
            return {}
        
        self.running = False
        self.end_time = time.time()
        
        # 等待收集线程结束
        if self.collecting_thread:
            self.collecting_thread.join(timeout=2)
        
        # 收集最终指标
        self._collect_single_metrics()
        
        # 计算统计数据
        stats = self._calculate_statistics()
        
        self.logger.info("性能追踪结束")
        return stats
    
    def _collect_metrics(self):
        """
        在单独线程中持续收集性能指标
        """
        while self.running:
            try:
                self._collect_single_metrics()
                time.sleep(self.collection_interval)
            except Exception as e:
                self.logger.error(f"收集性能指标异常: {str(e)}")
    
    def _collect_single_metrics(self):
        """
        收集单次性能指标
        """
        current_time = time.time() - self.start_time if self.start_time else 0
        
        # 收集CPU使用率
        try:
            cpu_usage = psutil.cpu_percent(interval=0.1)
            self.metrics['cpu_usage'].append((current_time, cpu_usage))
        except Exception as e:
            self.logger.warning(f"收集CPU使用率失败: {str(e)}")
        
        # 收集内存使用情况
        try:
            memory_info = psutil.virtual_memory()
            memory_used_mb = memory_info.used / (1024 * 1024)  # 转换为MB
            self.metrics['memory_usage'].append((current_time, memory_used_mb))
        except Exception as e:
            self.logger.warning(f"收集内存使用率失败: {str(e)}")
    
    def _calculate_statistics(self) -> Dict[str, Any]:
        """
        计算性能统计数据
        
        Returns:
            统计数据字典
        """
        if not self.start_time or not self.end_time:
            return {}
        
        total_duration = self.end_time - self.start_time
        
        # 计算CPU统计
        cpu_values = [value[1] for value in self.metrics['cpu_usage']]
        avg_cpu = sum(cpu_values) / len(cpu_values) if cpu_values else 0
        max_cpu = max(cpu_values) if cpu_values else 0
        
        # 计算内存统计
        memory_values = [value[1] for value in self.metrics['memory_usage']]
        avg_memory = sum(memory_values) / len(memory_values) if memory_values else 0
        max_memory = max(memory_values) if memory_values else 0
        
        # 计算各阶段执行时间
        phase_durations = {}
        for phase, start_time in self.phase_start_times.items():
            end_time = time.time() if phase != 'current' else self.end_time
            phase_durations[phase] = end_time - start_time
        
        # 计算资源利用率
        resource_utilization = {
            'cpu': {
                'average': avg_cpu,
                'max': max_cpu,
                'utilization_percentage': min(avg_cpu / psutil.cpu_count(), 100)
            },
            'memory': {
                'average_mb': avg_memory,
                'max_mb': max_memory,
                'average_percentage': (avg_memory / (psutil.virtual_memory().total / (1024 * 1024))) * 100
            }
        }
        
        # 计算效率指标
        efficiency = {
            'total_duration': total_duration,
            'resource_utilization': resource_utilization,
            'phase_durations': phase_durations
        }
        
        # 如果有基准数据，计算性能提升
        if self.baseline_data:
            improvement = self._calculate_improvement(efficiency, self.baseline_data)
            efficiency['performance_improvement'] = improvement
        
        return efficiency
    
    def _calculate_improvement(self, current: Dict[str, Any], baseline: Dict[str, Any]) -> Dict[str, float]:
        """
        计算性能提升百分比
        
        Args:
            current: 当前性能数据
            baseline: 基准性能数据
            
        Returns:
            性能提升数据
        """
        # 计算时间减少百分比
        time_improvement = 0
        if baseline.get('total_duration', 0) > 0:
            time_reduction = baseline['total_duration'] - current['total_duration']
            time_improvement = (time_reduction / baseline['total_duration']) * 100
        
        # 计算资源效率提升（完成相同工作使用更少资源）
        resource_efficiency = 0
        if 'resource_utilization' in baseline and 'resource_utilization' in current:
            # CPU效率提升
            baseline_cpu = baseline['resource_utilization']['cpu'].get('average', 1)
            current_cpu = current['resource_utilization']['cpu'].get('average', 1)
            cpu_efficiency = 1 - (current_cpu / baseline_cpu)
            
            # 内存效率提升
            baseline_memory = baseline['resource_utilization']['memory'].get('average_mb', 1)
            current_memory = current['resource_utilization']['memory'].get('average_mb', 1)
            memory_efficiency = 1 - (current_memory / baseline_memory)
            
            resource_efficiency = (cpu_efficiency + memory_efficiency) / 2 * 100
        
        # 综合性能提升（时间减少是主要因素）
        overall_improvement = time_improvement * 0.8 + resource_efficiency * 0.2
        
        return {
            'time_reduction_percentage': max(0, time_improvement),
            'resource_efficiency_improvement': max(0, resource_efficiency),
            'overall_performance_improvement': max(0, overall_improvement)
        }
    
    def start_phase(self, phase_name: str):
        """
        开始记录一个新的执行阶段
        
        Args:
            phase_name: 阶段名称
        """
        self.phase_start_times[phase_name] = time.time()
        self.phase_start_times['current'] = time.time()
        self.logger.debug(f"开始阶段: {phase_name}")
    
    def end_phase(self, phase_name: str):
        """
        结束记录一个执行阶段
        
        Args:
            phase_name: 阶段名称
        """
        if phase_name in self.phase_start_times:
            start_time = self.phase_start_times[phase_name]
            duration = time.time() - start_time
            self.metrics['execution_times'][phase_name] = duration
            self.logger.debug(f"结束阶段: {phase_name}, 耗时: {duration:.3f}秒")
        else:
            self.logger.warning(f"尝试结束未开始的阶段: {phase_name}")
    
    def set_baseline(self, baseline_data: Dict[str, Any]):
        """
        设置基准性能数据用于比较
        
        Args:
            baseline_data: 基准性能数据
        """
        self.baseline_data = baseline_data
        self.logger.info("已设置性能基准数据")
    
    def export_report(self, output_path: Optional[str] = None) -> str:
        """
        导出性能报告
        
        Args:
            output_path: 输出路径，None使用默认路径
            
        Returns:
            报告文件路径
        """
        if not output_path:
            # 使用默认路径
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            output_dir = "./reports"
            os.makedirs(output_dir, exist_ok=True)
            output_path = os.path.join(output_dir, f"performance_report_{timestamp}.json")
        
        # 生成报告数据
        report = {
            'timestamp': datetime.now().isoformat(),
            'execution_summary': self._calculate_statistics(),
            'raw_metrics': self.metrics
        }
        
        try:
            # 确保目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 保存报告
            with open(output_path, 'w', encoding='utf-8') as f:
                json.dump(report, f, indent=2, ensure_ascii=False)
            
            self.logger.info(f"性能报告已导出到: {output_path}")
            return output_path
        except Exception as e:
            self.logger.error(f"导出性能报告失败: {str(e)}")
            raise
    
    def calculate_throughput(self, items_processed: int, duration: float = None) -> float:
        """
        计算吞吐量（每秒处理的项目数）
        
        Args:
            items_processed: 处理的项目数
            duration: 处理时间，None使用总执行时间
            
        Returns:
            吞吐量
        """
        if duration is None:
            if not self.start_time:
                return 0
            duration = time.time() - self.start_time if not self.end_time else self.end_time - self.start_time
        
        if duration <= 0:
            return 0
        
        throughput = items_processed / duration
        
        # 更新吞吐量记录
        self.metrics['throughput']['items_processed'] = items_processed
        self.metrics['throughput']['duration'] = duration
        self.metrics['throughput']['throughput_per_second'] = throughput
        
        return throughput
    
    def reset(self):
        """
        重置性能追踪器
        """
        self.start_time = None
        self.end_time = None
        self.metrics = {
            'cpu_usage': [],
            'memory_usage': [],
            'execution_times': {},
            'throughput': {},
            'resource_utilization': {}
        }
        self.phase_start_times = {}
        self.running = False
        self.logger.info("性能追踪器已重置")

# 全局性能追踪器实例
_performance_tracker_instance = None
_instance_lock = threading.Lock()

def get_performance_tracker() -> PerformanceTracker:
    """
    获取全局性能追踪器实例
    
    Returns:
        PerformanceTracker实例
    """
    global _performance_tracker_instance
    with _instance_lock:
        if _performance_tracker_instance is None:
            _performance_tracker_instance = PerformanceTracker()
    return _performance_tracker_instance

# 便捷函数
def start_tracking():
    """便捷函数：开始性能追踪"""
    return get_performance_tracker().start()

def stop_tracking() -> Dict[str, Any]:
    """便捷函数：停止性能追踪并返回数据"""
    return get_performance_tracker().stop()

def start_phase(phase_name: str):
    """便捷函数：开始阶段计时"""
    return get_performance_tracker().start_phase(phase_name)

def end_phase(phase_name: str):
    """便捷函数：结束阶段计时"""
    return get_performance_tracker().end_phase(phase_name)

def calculate_throughput(items_processed: int, duration: float = None) -> float:
    """便捷函数：计算吞吐量"""
    return get_performance_tracker().calculate_throughput(items_processed, duration)